%% @author jovial
%% @doc @todo Add description to criatura.

-module(criatura).

-define(INTERVALO_FOME_PREDADOR, 120).
-define(INTERVALO_PROCRIACAO_PREDADOR, 120).
-define(INTERVALO_PROCRIACAO_PRESA, 50).

-export([new/1, id/1, isPredador/1, morreuCausasNaturais/1, podeComer/2, podeProcriar/2, procriou/1, comeu/1, novoCiclo/1, 
		getTipo/1,getCiclo/1,getCicloRefeicao/1, getIntervaloMorteFome/0, aptoParaProcriar/1, podeSeMover/1]).
-record(criatura, {id, tipo, ciclo = 0, ultimaRefeicao = 0, ultimoAcasalamento = 0}).

%% ====================================================================
%% API functions
%% ====================================================================

new(presa) ->
	#criatura{id = gerarIdentificador(), tipo = presa};
new(predador) ->
	#criatura{id = gerarIdentificador(), tipo = predador}.

id(#criatura{id = ID, tipo = Tipo}) ->
	{ID, Tipo}.

isPredador(Criatura) ->
	Criatura#criatura.tipo =:= predador.

morreuCausasNaturais(Criatura) when Criatura#criatura.tipo =:= predador ->
	Ciclo = Criatura#criatura.ciclo,
	Ultimo = Criatura#criatura.ultimaRefeicao,
	(Ciclo - Ultimo >= ?INTERVALO_FOME_PREDADOR) or (random:uniform() > 0.999);
morreuCausasNaturais(Criatura) when Criatura#criatura.tipo =:= presa ->
	random:uniform() > 0.992.

podeComer(Criatura1, Criatura2)
  when Criatura1#criatura.tipo =:= predador, Criatura2#criatura.tipo =:= presa ->
	true;
podeComer(_, _) ->
	false.

podeProcriar(Criatura1, Criatura2)
  when Criatura1#criatura.tipo =:= Criatura2#criatura.tipo ->
	aptoParaProcriar(Criatura1) and aptoParaProcriar(Criatura2);
podeProcriar(_, _) ->
	false.

procriou(Criatura) ->
	Criatura#criatura{ultimoAcasalamento = Criatura#criatura.ciclo}.

comeu(Criatura) ->
	Criatura#criatura{ultimaRefeicao = Criatura#criatura.ciclo}.

novoCiclo(Criatura) ->
	Criatura#criatura{ciclo = Criatura#criatura.ciclo + 1}.

getTipo(#criatura{tipo = Tipo}) ->
	Tipo.

getCiclo(Criatura)->
	Criatura#criatura.ciclo.

getCicloRefeicao(Criatura)->
	Criatura#criatura.ultimaRefeicao.

getIntervaloMorteFome()->
	?INTERVALO_FOME_PREDADOR.

aptoParaProcriar(Criatura) ->
	Ciclo = Criatura#criatura.ciclo,
	Ultimo = Criatura#criatura.ultimoAcasalamento,
	(Ciclo - Ultimo >= obterIntervaloProcriacao(Criatura)).

podeSeMover(Criatura) when Criatura#criatura.tipo =:= predador ->
	true;
podeSeMover(Criatura) when Criatura#criatura.tipo =:= presa ->
	Criatura#criatura.ciclo rem 2 =:= 0.

%% ====================================================================
%% Internal functions
%% ====================================================================

obterIntervaloProcriacao(Criatura) when Criatura#criatura.tipo =:= predador ->
	?INTERVALO_PROCRIACAO_PREDADOR;
obterIntervaloProcriacao(Criatura) when Criatura#criatura.tipo =:= presa ->
	?INTERVALO_PROCRIACAO_PRESA.

gerarIdentificador() ->
	erlang:phash2({node(), now()}).

